###############################################################################
# This file defines the macros that ParaView-based clients can use of creating
# custom ParaView client builds with custom branding and configuration.
#
# build_paraview_client(
#   # The name for this client. This is the name used for the executable created.
#   paraview
#
#   # Optional name for the application (If none is specified then the
#   # client-name is used.
#   APPLICATION_NAME "ParaView"
#
#   # This is the title bar text (optional).
#
#   TITLE "Kitware ParaView"
#
#   # This is the organization name.
#   ORGANIZATION "Kitware Inc."
#
#   # PNG Image to be used for the Splash screen. If none is provided,
#   # splash screen is not shown/used.
#   SPLASH_IMAGE "${CMAKE_CURRENT_SOURCE_DIR}/Splash.png"
#
#   # Provide version information for the client.
#   VERSION_MAJOR ${PARAVIEW_VERSION_MAJOR}
#   VERSION_MINOR ${PARAVIEW_VERSION_MINOR}
#   VERSION_PATCH ${PARAVIEW_VERSION_PATCH}
#
#   # Icon to be used for the Mac bundle.
#   BUNDLE_ICON   "${CMAKE_CURRENT_SOURCE_DIR}/Icon.icns"
#
#   # Icon to be used for the Windows application.
#   APPLICATION_ICON "${CMAKE_CURRENT_SOURCE_DIR}/Icon.ico"
#
#   # Name of the class to use for the main window. If none is specified,
#   # default QMainWindow will be used.
#   PVMAIN_WINDOW QMainWindow-subclass
#   PVMAIN_WINDOW_INCLUDE QMainWindow-subclass-header
#
#   # Next specify the plugins that are needed to be built and loaded on startup
#   # for this client to work. These must be specified in the order that they
#   # should be loaded. The name is the name of the plugin specified in the
#   # add_paraview_plugin call.
#   # Currently, only client-based plugins are supported. i.e. no effort is made
#   # to load the plugins on the server side when a new server connection is made.
#   # That may be added in future, if deemed necessary.
#   REQUIRED_PLUGINS PointSpritePlugin
#
#   # Next specify the plugin that are not required, but if available, should be
#   # loaded on startup. These must be specified in the order that they
#   # should be loaded. The name is the name of the plugin specified in the
#   # add_paraview_plugin call.
#   # Currently, only client-based plugins are supported. i.e. no effort is made
#   # to load the plugins on the server side when a new server connection is made.
#   # That may be added in future, if deemed necessary.
#   OPTIONAL_PLUGINS ClientGraphView ClientTreeView
#
#   # Extra targets that this executable depends on. Useful only if you are
#   # building extra libraries for your application.
#   EXTRA_DEPENDENCIES blah1 blah2
#
#   # GUI Configuration XMLs that are used to configure the client eg. readers,
#   # writers, sources menu, filters menu etc.
#   GUI_CONFIGURATION_XMLS <list of xml files>
#
#   # The Qt compressed help file (*.qch) which provides the documentation for the
#   # application. *.qch files are typically generated from *.qhp files using
#   # the qhelpgenerator executable.
#   COMPRESSED_HELP_FILE MyApp.qch
#
#   # Additional source files.
#   SOURCES <list of source files>
#
#   # If this option is present, then this macro will create a library named
#   # pq{Name}Initializer with all the source components generated by this macro
#   # that the executable links against. Otherwise, for sake of simplicity no
#   # extra library is created.
#   MAKE_INITIALIZER_LIBRARY
#
#   # Optionally specify install destinations.  See CMake install() command
#   # documentation for meaning of RUNTIME, LIBRARY, ARCHIVE, and BUNDLE.
#   INSTALL_RUNTIME_DIR "bin"
#   INSTALL_LIBRARY_DIR "lib/<appname>-<major>.<minor>"
#   INSTALL_ARCHIVE_DIR "lib/<appname>-<major>.<minor>"
#   INSTALL_BUNDLE_DIR  "bin" # default is the INSTALL_RUNTIME_DIR
#
#   # Deprecated.  Use INSTALL_RUNTIME_DIR and INSTALL_BUNDLE_DIR instead.
#   INSTALL_BIN_DIR "bin"
#
#   # Deprecated.  Use INSTALL_LIBRARY_DIR and INSTALL_ARCHIVE_DIR instead.
#   INSTALL_LIB_DIR "lib"
#   )
#
###############################################################################
include(pvForwardingExecutable)

FUNCTION(build_paraview_client BPC_NAME)
  PV_PARSE_ARGUMENTS(BPC
    "APPLICATION_NAME;TITLE;ORGANIZATION;SPLASH_IMAGE;VERSION_MAJOR;VERSION_MINOR;VERSION_PATCH;BUNDLE_ICON;APPLICATION_ICON;REQUIRED_PLUGINS;OPTIONAL_PLUGINS;PVMAIN_WINDOW;PVMAIN_WINDOW_INCLUDE;EXTRA_DEPENDENCIES;GUI_CONFIGURATION_XMLS;COMPRESSED_HELP_FILE;SOURCES;INSTALL_RUNTIME_DIR;INSTALL_LIBRARY_DIR;INSTALL_ARCHIVE_DIR;INSTALL_BUNDLE_DIR;INSTALL_BIN_DIR;INSTALL_LIB_DIR"
    "MAKE_INITIALIZER_LIBRARY"
    ${ARGN}
    )

  # Version numbers are required. Throw an error is not set correctly.
  IF (NOT DEFINED BPC_VERSION_MAJOR OR NOT DEFINED BPC_VERSION_MINOR OR NOT DEFINED BPC_VERSION_PATCH)
    MESSAGE(ERROR
      "VERSION_MAJOR, VERSION_MINOR and VERSION_PATCH must be specified")
  ENDIF ()

  # If no title is provided, make one up using the name.
  if(DEFINED BPC_TITLE)
    set (BPC_HAS_TITLE 1)
  else()
    set (BPC_HAS_TITLE 0)
  endif()
  pv_set_if_not_set(BPC_TITLE "${BPC_NAME}")
  pv_set_if_not_set(BPC_APPLICATION_NAME "${BPC_NAME}")
  pv_set_if_not_set(BPC_ORGANIZATION "Humanity")
  if(NOT DEFINED BPC_INSTALL_RUNTIME_DIR AND DEFINED BPC_INSTALL_BIN_DIR)
    set(BPC_INSTALL_RUNTIME_DIR "${BPC_INSTALL_BIN_DIR}")
  endif()
  if(NOT DEFINED BPC_INSTALL_LIBRARY_DIR AND DEFINED BPC_INSTALL_LIB_DIR)
    set(BPC_INSTALL_LIBRARY_DIR "${BPC_INSTALL_LIB_DIR}")
  endif()
  if(NOT DEFINED BPC_INSTALL_BUNDLE_DIR AND DEFINED BPC_INSTALL_BIN_DIR)
    set(BPC_INSTALL_BUNDLE_DIR "${BPC_INSTALL_BIN_DIR}")
  endif()
  pv_set_if_not_set(BPC_INSTALL_RUNTIME_DIR "bin")
  pv_set_if_not_set(BPC_INSTALL_LIBRARY_DIR
      "lib/${BPC_NAME}-${BPC_VERSION_MAJOR}.${BPC_VERSION_MINOR}")
  pv_set_if_not_set(BPC_INSTALL_ARCHIVE_DIR
      "lib/${BPC_NAME}-${BPC_VERSION_MAJOR}.${BPC_VERSION_MINOR}")
  pv_set_if_not_set(BPC_INSTALL_BUNDLE_DIR "${BPC_INSTALL_RUNTIME_DIR}")

  SET (branding_source_dir "${ParaView_CMAKE_DIR}")

  # If APPLICATION_ICON is specified, use that for the windows executable.
  IF (WIN32 AND BPC_APPLICATION_ICON)
    FILE (WRITE "${CMAKE_CURRENT_BINARY_DIR}/Icon.rc"
      "// Icon with lowest ID value placed first to ensure application icon\n"
      "// remains consistent on all systems.\n"
      "IDI_ICON1 ICON \"${BPC_APPLICATION_ICON}\"")
    SET(exe_icon "${CMAKE_CURRENT_BINARY_DIR}/Icon.rc")
  ENDIF ()

  # executable_flags are used to pass options to add_executable(..) call such as
  # WIN32 or MACOSX_BUNDLE
  set (executable_flags)

  # If BPC_BUNDLE_ICON is set, setup the macosx bundle.
  IF (APPLE)
    IF (BPC_BUNDLE_ICON)
      GET_FILENAME_COMPONENT(bundle_icon_file "${BPC_BUNDLE_ICON}" NAME)
      SET(apple_bundle_sources ${bundle_icon_file})
      SET_SOURCE_FILES_PROPERTIES(
        ${BPC_BUNDLE_ICON}
        PROPERTIES
        MACOSX_PACKAGE_LOCATION Resources
        )
    ENDIF ()
    IF (IS_DIRECTORY "${QT_QTGUI_LIBRARY_RELEASE}")
      GET_FILENAME_COMPONENT(qt_menu_nib
        "${QT_QTGUI_LIBRARY_RELEASE}/Resources/qt_menu.nib"
        REALPATH)
    ELSE ()
      GET_FILENAME_COMPONENT(qt_menu_nib
        "${QT_LIBRARY_DIR}/Resources/qt_menu.nib"
        REALPATH)
    ENDIF ()

    set(qt_menu_nib_sources
      "${qt_menu_nib}/classes.nib"
      "${qt_menu_nib}/info.nib"
      "${qt_menu_nib}/keyedobjects.nib"
      )
    SET_SOURCE_FILES_PROPERTIES(
      ${qt_menu_nib_sources}
      PROPERTIES
      MACOSX_PACKAGE_LOCATION Resources/qt_menu.nib
      )
    SET(executable_flags MACOSX_BUNDLE)
  ENDIF ()

  IF(WIN32)
    LINK_DIRECTORIES(${QT_LIBRARY_DIR})
    set (executable_flags WIN32)
  ENDIF()

  pv_set_if_not_set(BPC_PVMAIN_WINDOW "QMainWindow")
  pv_set_if_not_set(BPC_PVMAIN_WINDOW_INCLUDE "QMainWindow")

  SET (BPC_HAS_GUI_CONFIGURATION_XMLS 0)
  IF (BPC_GUI_CONFIGURATION_XMLS)
    SET (BPC_HAS_GUI_CONFIGURATION_XMLS 1)
  ENDIF ()

  set (ui_resources)
  set (ui_resource_init "")

  # If a splash image is specified, put that in a Qt resource file
  # and pass the name along to branded_paraview_initializer.cxx.
  if(DEFINED BPC_SPLASH_IMAGE)
    # We name the splash image as "SplashImage.img". That way, the
    # pqAboutDialog and other UI components can automatically pick
    # it up.
    set(splash_img "${CMAKE_CURRENT_BINARY_DIR}/SplashImage.img")
    configure_file("${BPC_SPLASH_IMAGE}" "${splash_img}" COPYONLY)
    set(BPC_SPLASH_RESOURCE ":/${BPC_NAME}/SplashImage.img")
    # Generate a resource file for the splash image.
    set(splash_qrc "${CMAKE_CURRENT_BINARY_DIR}/${BPC_NAME}_splash.qrc")
    generate_qt_resource_from_files("${splash_qrc}" "/${BPC_NAME}" ${splash_img})
    list(APPEND ui_resources "${splash_qrc}")
    set(ui_resource_init
      "${ui_resource_init}  Q_INIT_RESOURCE(${BPC_NAME}_splash);\n")
  endif()

  if (BPC_GUI_CONFIGURATION_XMLS)
    set (outfile "${CMAKE_CURRENT_BINARY_DIR}/${BPC_NAME}_configuration.qrc")
    GENERATE_QT_RESOURCE_FROM_FILES("${outfile}"
      "/${BPC_NAME}/Configuration"
      "${BPC_GUI_CONFIGURATION_XMLS}")
    list(APPEND ui_resources "${outfile}")
    set(ui_resource_init
      "${ui_resource_init}  Q_INIT_RESOURCE(${BPC_NAME}_configuration);\n")
  endif ()

  IF (BPC_COMPRESSED_HELP_FILE)
    # If a help collection file is specified, create a resource from it so that
    # when the ParaView help system can locate it at runtime and show the
    # appropriate help when the user asks for it. The
    set (outfile "${CMAKE_CURRENT_BINARY_DIR}/${BPC_NAME}_help.qrc")
    GENERATE_QT_RESOURCE_FROM_FILES("${outfile}"
      "/${BPC_APPLICATION_NAME}/Documentation"
      "${BPC_COMPRESSED_HELP_FILE};")
    SET_SOURCE_FILES_PROPERTIES(${outfile}
      PROPERTIES OBJECT_DEPENDS "${BPC_COMPRESSED_HELP_FILE}")
    SET (ui_resources ${ui_resources} "${outfile}")
    set (ui_resource_init
      "${ui_resource_init}  Q_INIT_RESOURCE(${BPC_NAME}_help);\n")
  ENDIF ()

  INCLUDE(ParaViewQt)
  pv_find_package_qt(qt_targets REQUIRED QUIET
    QT5_COMPONENTS Widgets)
  pv_qt_add_resources(rcs_sources ${ui_resources})

  SOURCE_GROUP("Resources" FILES
    ${ui_resources}
    ${exe_icon}
    )
  SOURCE_GROUP("Generated" FILES
    ${rcs_sources}
    )
  CONFIGURE_FILE(${branding_source_dir}/branded_paraview_main.cxx.in
                 ${CMAKE_CURRENT_BINARY_DIR}/${BPC_NAME}_main.cxx @ONLY)
  CONFIGURE_FILE(${branding_source_dir}/branded_paraview_initializer.cxx.in
                 ${CMAKE_CURRENT_BINARY_DIR}/pq${BPC_NAME}Initializer.cxx @ONLY)
  CONFIGURE_FILE(${branding_source_dir}/branded_paraview_initializer.h.in
                 ${CMAKE_CURRENT_BINARY_DIR}/pq${BPC_NAME}Initializer.h @ONLY)

  # If BPC_MAKE_INITIALIZER_LIBRARY is set, then we are creating a separate
  # library for the initializer, otherwise we don't create a separate library to
  # keep things simple.
  SET (EXE_SRCS pq${BPC_NAME}Initializer.cxx
               ${rcs_sources}
               ${BPC_SOURCES})

  IF (BPC_MAKE_INITIALIZER_LIBRARY)
    ADD_LIBRARY(pq${BPC_NAME}Initializer SHARED
                ${EXE_SRCS}
                )
    SET (EXE_SRCS)
    TARGET_LINK_LIBRARIES(pq${BPC_NAME}Initializer
      LINK_PRIVATE
        pqApplicationComponents
        vtkPVServerManagerApplication
        ${BPC_EXTRA_DEPENDENCIES}
        ${qt_targets}
      )

    IF (PV_INSTALL_LIB_DIR)
      INSTALL(TARGETS pq${BPC_NAME}Initializer
            DESTINATION ${PV_INSTALL_LIB_DIR}
            COMPONENT Runtime)
    ENDIF ()
  ENDIF ()

  SET (PV_EXE_LIST ${BPC_NAME})

  # needed to set up shared forwarding correctly.
  pv_add_executable_with_forwarding2(pv_exe_suffix
                 "${PARAVIEW_LIBRARY_DIRS}"
                 "../${PARAVIEW_INSTALL_LIB_DIR}"
                 "${BPC_INSTALL_LIBRARY_DIR}"
                 ${BPC_NAME}
                 ${executable_flags}
                 ${BPC_NAME}_main.cxx
                 ${exe_icon}
                 ${apple_bundle_sources}
                 ${EXE_SRCS}
                 )
  TARGET_LINK_LIBRARIES(${BPC_NAME}
      LINK_PRIVATE
        pqApplicationComponents
        vtkPVServerManagerApplication
        vtksys
        ${qt_targets}
        ${BPC_EXTRA_DEPENDENCIES}
    )

  IF (BPC_MAKE_INITIALIZER_LIBRARY)
    TARGET_LINK_LIBRARIES(${BPC_NAME}
      LINK_PRIVATE
        pq${BPC_NAME}Initializer)
  ENDIF ()

  if (MINGW)
    # needed for dupenv_s
    target_link_libraries (${BPC_NAME} LINK_PRIVATE msvcr90)
  endif ()

  if (pv_exe_suffix)
    install(TARGETS ${BPC_NAME}
            RUNTIME DESTINATION "${BPC_INSTALL_LIBRARY_DIR}"
            COMPONENT Runtime)
  endif()
  install(TARGETS ${BPC_NAME}${pv_exe_suffix}
          RUNTIME DESTINATION "${BPC_INSTALL_RUNTIME_DIR}"
          LIBRARY DESTINATION "${BPC_INSTALL_LIBRARY_DIR}"
          ARCHIVE DESTINATION "${BPC_INSTALL_ARCHIVE_DIR}"
          BUNDLE DESTINATION  "${BPC_INSTALL_BUNDLE_DIR}"
          COMPONENT Runtime)

  IF (APPLE)
    IF (BPC_BUNDLE_ICON)
      SET_TARGET_PROPERTIES(${BPC_NAME} PROPERTIES
        MACOSX_BUNDLE_ICON_FILE ${bundle_icon_file})
    ENDIF ()
    SET_TARGET_PROPERTIES(${BPC_NAME} PROPERTIES
      MACOSX_BUNDLE_BUNDLE_NAME "${BPC_APPLICATION_NAME}")
    string(TOLOWER ${BPC_ORGANIZATION} BPC_ORGANIZATION_LOWER)
    SET_TARGET_PROPERTIES(${BPC_NAME} PROPERTIES
      MACOSX_BUNDLE_GUI_IDENTIFIER "org.${BPC_ORGANIZATION_LOWER}.${BPC_APPLICATION_NAME}")
    SET_TARGET_PROPERTIES(${BPC_NAME} PROPERTIES
      MACOSX_BUNDLE_SHORT_VERSION_STRING "${BPC_VERSION_MAJOR}.${BPC_VERSION_MINOR}.${BPC_VERSION_PATCH}")
    if (NOT PARAVIEW_DO_UNIX_STYLE_INSTALLS)
      set_target_properties("${BPC_NAME}" PROPERTIES
        INSTALL_RPATH "@executable_path/../Libraries;@executable_path/../Plugins")
    endif ()
  ENDIF ()
ENDFUNCTION()
